import { expect } from 'chai';
import sinon from 'sinon';
import oss from '../../src/oss';
import certificate from '../../src/certificate';
import {listFiles, uploadReport} from '../../src/testCase/uploadReport'
import path from 'path';
import * as fs from 'fs'
import * as glob from 'glob';


describe('uploadReport Function', () => {
    const sandbox = sinon.createSandbox();
    const mockEndpoint = 'mock-endpoint';
    const mockFlowJobToken = 'mock-token';
    const mockCertificate = {
        accessKeyId: 'mock-access-key-id',
        accessKeySecret: 'mock-access-key-secret',
        securityToken: 'mock-security-token',
        bucketName: 'mock-bucket-name',
        ossPathPrefix: 'mock/oss/path'
    };
    let getOssRamStsCertificateStub: sinon.SinonStub
    let uploadStub: sinon.SinonStub;
    let globStub: sinon.SinonStub;
    let sizeCheckStub: sinon.SinonStub;

    beforeEach(() => {
        process.env['endpoint'] = mockEndpoint;
        process.env['FLOW_JOB_TOKEN'] = mockFlowJobToken;
        process.env['PIPELINE_ID'] = 'mock-pipeline-id';
        getOssRamStsCertificateStub = sandbox.stub(certificate, 'getOssRamStsCertificate').resolves(mockCertificate);
        uploadStub = sandbox.stub(oss, 'upload').resolves();
        globStub = sandbox.stub(glob, 'glob');
        // eslint-disable-next-line @typescript-eslint/no-var-requires
        sizeCheckStub = sandbox.stub(require('../../src/testCase/sizeCheck'), 'sizeCheck').resolves();
    });

    afterEach(() => {
        sandbox.restore();
    });

    it('should throw an error if FLOW_JOB_TOKEN is missing', async () => {
        const reportPath = 'path/to/report.txt';
        delete process.env['FLOW_JOB_TOKEN'];
        try{
            await uploadReport(reportPath);
        }catch (e:any){
            expect(e.message).to.equal('missing FLOW_JOB_TOKEN');
        }
    });

    it('should upload report and return objectKey - non-html', async () => {
        const reportPath = 'path/to/report.txt';

        const objectKey = await uploadReport(reportPath);

        expect(getOssRamStsCertificateStub.calledOnceWith(mockFlowJobToken, certificate.OssBucketType.ASSETS)).to.be.true;
        expect(uploadStub.calledOnce).to.be.true;

        // Verify the object key format
        const reportIndex = path.basename(reportPath);
        // As UUID is dynamic, use a regex to match the expected format
        expect(objectKey).to.match(new RegExp(`^${mockCertificate.ossPathPrefix}/mock-pipeline-id/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/${reportIndex}$`));
    });

    it('should upload all files under directory and return objectKey - html', async () => {
        const reportPath = 'path/to/report.html';
        globStub.resolves(['report.html','image.png','css/t1.css','css/t2.css'])

        const objectKey = await uploadReport(reportPath);

        expect(getOssRamStsCertificateStub.calledOnceWith(mockFlowJobToken, certificate.OssBucketType.ASSETS)).to.be.true;
        expect(uploadStub.calledWith(sinon.match.any,'path/to/report.html',sinon.match.any,sinon.match.any)).to.be.true;
        expect(uploadStub.calledWith(sinon.match.any,'path/to/image.png',sinon.match.any,sinon.match.any)).to.be.true;
        expect(uploadStub.calledWith(sinon.match.any,'path/to/css/t1.css',sinon.match.any,sinon.match.any)).to.be.true;
        expect(uploadStub.calledWith(sinon.match.any,'path/to/css/t2.css',sinon.match.any,sinon.match.any)).to.be.true;


        // Verify the object key format
        const reportIndex = path.basename(reportPath);
        // As UUID is dynamic, use a regex to match the expected format
        expect(objectKey).to.match(new RegExp(`^${mockCertificate.ossPathPrefix}/mock-pipeline-id/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/${reportIndex}$`));
    });


});

describe('listFiles Function', () => {
    const testDir = './testDir';

    before(() => {
        fs.mkdirSync(testDir);
    });

    after(() => {
        fs.rmSync(testDir, { recursive: true, force: true });
    });

    it('should list files under the directory', async () => {
        fs.writeFileSync(path.join(testDir, 'file1.txt'), 'Hello, world!');
        fs.writeFileSync(path.join(testDir, 'file2.txt'), 'Another file');

        const subDir = path.join(testDir, 'subDir');
        fs.mkdirSync(subDir);
        fs.writeFileSync(path.join(subDir, 'file3.txt'), '3rd file');
        const files = await listFiles(testDir);
        expect(files).to.deep.equal(['file2.txt', 'file1.txt', 'subDir/file3.txt']);

    })
})